//servidor nivel 2
#include<stdlib.h>
#include<stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <pthread.h>
#include <time.h>

#define TAMBUFFER 1000
#define NUMTOT 250
#define PORT1 1234 //ouve nas portas
#define PORT2 1235


typedef struct{
	int port;
	char* vetor;	
	double tempo;
}thread_arg;

void* recebeDadosCliente(void* args)
{
	thread_arg* argumentos = (thread_arg*) args;
	char* vetorDados = (char*) argumentos->vetor; //referencia para vetor na main
	
	int sockfd, newsockfd, portno;
	socklen_t clilen;
	char *buffer;
	struct sockaddr_in serv_addr, cli_addr;
	int n;
	clock_t startTime;
	double tempo;
	
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if(sockfd < 0)
	{
		printf("Erro na criacao do socket\n");
	}
	
	bzero((char*) &serv_addr, sizeof(serv_addr));
	portno = argumentos->port;
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_addr.s_addr = INADDR_ANY;
	serv_addr.sin_port = htons(portno);
	
	if(bind(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0)
	{
		printf("Erro no bind");
	}
	else
	{
		printf("Aguardando conexao\n");
	}
	
	listen(sockfd, 5);
	clilen = sizeof(cli_addr);
	newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
	if(newsockfd < 0)
	{
		printf("Erro ao aceitar\n");
	}
	else
	{
		printf("Aceitou conexao\n");
	}
	
	buffer = (char*) malloc(TAMBUFFER*sizeof(char));
	//------------------------------------------------tempo de transmissao
	startTime = clock();
	n = read(newsockfd, buffer, TAMBUFFER);
	tempo =(double)(clock()-startTime)/CLOCKS_PER_SEC;
	argumentos->tempo = tempo;
	//-------------------------------------------------fim tempo de transmissao
	if(n < 0)
	{
		printf("Erro ao ler socket\n");
	}
	
	strcpy(vetorDados, buffer);
	close(sockfd);
	close(newsockfd);
	free(buffer);
}

double ordenaDados(char* vetChar1, char* vetChar2, int* vetOrdenado)
{
	int i=0,j=0,k=0;
	int *vetInt1 = (int*)malloc((NUMTOT/2)*sizeof(int));
	int *vetInt2 = (int*)malloc((NUMTOT/2)*sizeof(int));
	char* str1 = strtok(vetChar1, " ");
	clock_t startTime;
	double tempo;
	
	while(str1 != NULL)
	{
		vetInt1[i] = atoi(str1);
		str1 = strtok(NULL, " ");
		i++;
	}
	
	str1 = strtok(vetChar2, " ");
	i=0;	
	while(str1 != NULL)
	{
		vetInt2[i] = atoi(str1);
		str1 = strtok(NULL, " ");
		i++;
	}
	//----------------------------------------inicio tempo de ordenacao
	startTime = clock();
	i=0;
	j=0;
	for(k=0; k<NUMTOT; k++)
	{
		if(i == (NUMTOT/2))
		{
			vetOrdenado[k] = vetInt2[j++];
			continue;
		}
		if(j == (NUMTOT/2))
		{
			vetOrdenado[k] = vetInt1[i++];
			continue;
		}
		if(vetInt1[i] < vetInt2[j])
		{
			vetOrdenado[k] = vetInt1[i++];
		}
		else
		{
			vetOrdenado[k] = vetInt2[j++];
		}
	}
	tempo = (double)(clock()-startTime)/CLOCKS_PER_SEC;
	//-----------------------------------------fim tempo de ordenacao
	free(vetInt1);
	free(vetInt2);
	return tempo;
}

void converteIntToChar(int* vetorInt, char* vetorChar)
{
	int i;
	char *buffer = (char*) malloc((TAMBUFFER*2)*sizeof(char));
	char str[15];
	
	strcpy(buffer, "\0");
	strcpy(str, "\0");
	for(i=0; i< NUMTOT; i++)
	{
		sprintf(str, "%d ", vetorInt[i]);
		strcat(buffer, str);
		strcpy(str, "\0");
	}
	strcat(buffer, "\0");
	strcpy(vetorChar, buffer);
	free(buffer);
}

void enviaDadosServidor(char* host, int port, char* dados)
{
	int sockfd, portno = port, n;
	struct sockaddr_in serv_addr;
	struct hostent *server;
	
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if(sockfd < 0)
	{
		printf("Erro no socket\n");
	}
	
	server = gethostbyname(host);
	if(server == NULL)
	{
		printf("Erros no host\n");
	}
	
	bzero((char*) &serv_addr, sizeof(serv_addr));
	serv_addr.sin_family = AF_INET;
	bcopy((char*) server->h_addr, (char*)&serv_addr.sin_addr.s_addr, server->h_length);
	serv_addr.sin_port = htons(portno);
	
	if(connect(sockfd,(struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
	{
		printf("Erro na conexao");
		exit(1);
	}
	
	n = write(sockfd, dados, strlen(dados));
	
	if(n < 0)
	{
		printf("Erro de escrita em socket\n");
	}
	close(sockfd);
}

int main(int argc, char **argv)
{
	char* vetorDados1 = (char*) malloc(TAMBUFFER*sizeof(char));
	char* vetorDados2 = (char*) malloc(TAMBUFFER*sizeof(char));
	int *vetorOrdenado = (int*) malloc(NUMTOT*sizeof(int));
	char *dadosAEnviar = (char*) malloc((TAMBUFFER*2)*sizeof(char));
	int i;
	double tempoOrdenacao;
	
	pthread_t pid1, pid2;
	thread_arg arg1, arg2;
	
	if(argc < 3)
	{
		printf("Quantidade de argumentos errado: host, port\n");
		exit(1);
	}
	
	arg1.port = PORT1;
	arg2.port = PORT2;
	arg1.vetor = vetorDados1;
	arg2.vetor = vetorDados2;
	arg1.tempo = 0.0;
	arg2.tempo = 0.0;
	
	pthread_create(&pid1, NULL, &recebeDadosCliente, &arg1); //threads para atender 2 clientes
	pthread_create(&pid2, NULL, &recebeDadosCliente, &arg2);	
	pthread_join(pid1, NULL);	
	pthread_join(pid2, NULL);
	
	printf("Cliente 1:\n%s\n", arg1.vetor);
	printf("Tempo de transmissao: %.3lf\n", arg1.tempo);
	printf("Cliente 2:\n%s\n", arg2.vetor);
	printf("\nTempo de transmissao: %.3lf\n", arg2.tempo);
	
	//-----------------------------------------------------------ordena os dois vetores recebidos
	tempoOrdenacao= ordenaDados(arg1.vetor, arg2.vetor, vetorOrdenado);
	printf("\nVetor ordenado:\n");
	for(i=0; i< NUMTOT; i++)
	{
		printf("%d ", vetorOrdenado[i]);
	}
	printf("\nTempo de ordenacao: %.3lf\n", tempoOrdenacao);
	//----------------------------------------------------------envia vetor ordenado para servidor	
	//envia dados para servidor nivel 3
	converteIntToChar(vetorOrdenado, dadosAEnviar);
	enviaDadosServidor(argv[1], atoi(argv[2]), dadosAEnviar);
	
	
	return 0;
}

